<template>
  <UniForms v-bind="getProps" ref="formElRef" :model="formModel">
    <view class="form-items" :style="{ backgroundColor: isFormEditModel ? 'transparent' : '#fff' }">
      <template v-for="(schema, index) in getSchema" :key="schema.field">
        <FormToolbar
          :disabled="!isFormEditModel"
          :show-toolbar="currentShowToolbarFiled === schema.field"
          @click="setCurrentShowToolbarFiled(schema.field)"
          @toolbar-btn-click="(type) => handleToolbarBtnClick(type, schema)"
        >
          <FormTitle v-if="schema.component === 'Divider'" :title="schema.label" />
          <FormsItem
            v-else
            :id="`forms-item__${schema.field}`"
            :schema="schema"
            :formProps="getProps"
            :allDefaultValues="defaultValueRef"
            :formModel="formModel"
            :setFormModel="setFormModel"
            :onSchemaChange="onSchemaChange"
          >
            <template v-if="schema.slot" #default="{ model, field }">
              <slot :name="schema.slot" :model="model" :field="field"></slot>
              <slot name="dynamicSlot" :model="model" :field="field"></slot>
            </template>
          </FormsItem>
        </FormToolbar>
      </template>
    </view>
  </UniForms>

  <TButtonGroup
    v-if="getBtnGroupOptions && !isEmpty(getBtnGroupOptions)"
    :styles="getBtnGroupOptions?.styles"
    :position="getBtnGroupOptions?.position"
    :placeholder="getBtnGroupOptions?.placeholder"
  >
    <TButton
      v-if="getBtnGroupOptions?.custom"
      class="gutter-btn"
      v-bind="getBtnGroupOptions.custom"
      :customClass="getBtnGroupOptions.custom.customClass || 'cardBlackBtn'"
      @click="handleCustom"
    />
    <TButton
      v-if="getBtnGroupOptions?.reset"
      class="gutter-btn"
      v-bind="getBtnGroupOptions.reset"
      :customClass="getBtnGroupOptions.reset.customClass || 'cardBlackBtn'"
      @click="handleReset"
    />
    <TButton
      v-if="getBtnGroupOptions?.submit"
      class="gutter-btn"
      v-bind="getBtnGroupOptions.submit"
      :customClass="getBtnGroupOptions.submit.customClass || 'cardBtn'"
      @click="handleSubmit"
    />
  </TButtonGroup>
</template>

<script setup lang="ts">
  import UniForms from './uni_modules/uni-forms/uni-forms.vue';
  import { computed, onMounted, reactive, type Ref, ref, unref, watch } from 'vue';
  import { basicProps } from './props';
  import { type FormActionType, type FormProps, type FormSchema } from './types/form';
  import { deepMerge } from '@/utils';
  import { useFormEvents } from './hooks/useFormEvents';
  import { useFormValues } from './hooks/useFormValues';
  import { DATE_TYPE, defaultOnchangeCompoents, notSubmitComponents } from './helper';
  import { dateUtil } from '@/utils/dateUtil';
  import FormsItem from './components/FormsItem.vue';
  import FormTitle from './components/FormTitle.vue';
  import { type OnchangeArgument } from './types';
  import TButtonGroup from '@/components/TButtonGroup/index.vue';
  import TButton from '@/components/TButtonGroup/TButton.vue';
  import { cloneDeep, isFunction, set } from 'lodash-es';
  import { isEmpty } from '@/utils/is';
  import FormToolbar, { type ToolbarType } from './components/FormToolbar.vue';

  const formModel = reactive<Recordable>({});
  const isInitedDefaultRef = ref(false);
  const defaultValueRef = ref<Recordable>({});
  const formElRef = ref<Nullable<FormActionType>>(null);
  const schemaRef = ref<Nullable<FormSchema[]>>(null);

  const emit = defineEmits(['reset', 'submit', 'register', 'update:model', 'onSchemaChange']);

  const props = defineProps(basicProps);
  const propsRef = ref<Partial<FormProps>>({});

  const getProps = computed((): FormProps => {
    return { ...props, ...unref(propsRef) } as FormProps;
  });

  /** 是否是编辑模式 */
  const isFormEditModel = computed(() => getProps.value.formInteractionMode === 'edit');
  const currentShowToolbarFiled = ref<FormSchema['field']>();
  const setCurrentShowToolbarFiled = (field: FormSchema['field']) => {
    if (currentShowToolbarFiled.value === field) {
      currentShowToolbarFiled.value = void 0;
    } else {
      currentShowToolbarFiled.value = field;
    }
  };

  const getBtnGroupOptions = computed(() => {
    const { btnGroupOptions } = getProps.value;
    return btnGroupOptions;
  });

  const getSchema = computed((): FormSchema[] => {
    const schemas: FormSchema[] = unref(schemaRef)?.length
      ? unref(schemaRef)
      : (unref(getProps).schemas as any);
    for (const schema of schemas) {
      const { defaultValue, component } = schema;
      if (defaultValue && DATE_TYPE.includes(component)) {
        if (Array.isArray(defaultValue)) {
          const def: any[] = [];
          defaultValue.forEach((item) => {
            def.push(dateUtil(item));
          });
          schema.defaultValue = def;
        } else {
          schema.defaultValue = dateUtil(defaultValue);
        }
      }

      if (defaultOnchangeCompoents.includes(component)) {
        schema.isOnChange = true;
      }
    }
    return schemas as FormSchema[];
  });

  const { handleFormValues, initDefault } = useFormValues({
    emit,
    getSchema,
    formModel,
    defaultValueRef,
  });
  const {
    handleSubmit,
    setFieldsValue,
    clearValidate,
    validate,
    getFieldsValue,
    updateSchema,
    resetSchema,
    appendSchemaByField,
    removeSchemaByFiled,
    resetFields,
    scrollToField,
  } = useFormEvents({
    emit,
    getProps,
    formModel,
    getSchema,
    defaultValueRef,
    formElRef: formElRef as Ref<FormActionType>,
    schemaRef: schemaRef as Ref<FormSchema[]>,
    handleFormValues,
  });

  watch(
    () => unref(getProps).model,
    () => {
      const { model } = unref(getProps);
      if (!model) return;
      setFieldsValue(model);
    },
    {
      immediate: true,
    },
  );

  watch(
    () => unref(getProps).schemas,
    (schemas) => {
      !schemaRef.value && resetSchema(schemas ?? []);
    },
  );

  watch(
    () => getSchema.value,
    (schema) => {
      if (unref(isInitedDefaultRef)) {
        return;
      }
      if (schema?.length) {
        initDefault();
        isInitedDefaultRef.value = true;
      }
    },
  );

  async function setProps(formProps: Partial<FormProps>): Promise<void> {
    propsRef.value = deepMerge(unref(propsRef) || {}, formProps);
  }

  function setFormModel(key: string, value: any) {
    const item = getSchema.value.find((item) => item.field === key);
    if (item && notSubmitComponents.includes(item.component)) return;
    formModel[key] = value;
  }

  function onSchemaChange(op: OnchangeArgument) {
    emit('onSchemaChange', op);
  }

  function handleCustom() {
    const vals: Recordable = {};
    const rawVals = getFieldsValue();
    Object.keys(rawVals).forEach(
      (k) => rawVals[k] !== '' && rawVals[k] !== null && set(vals, k, rawVals[k]),
    );
    getBtnGroupOptions.value?.custom?.clickFn?.(vals);
  }

  function handleReset() {
    const op = unref(getBtnGroupOptions);
    const customClickFnc = op?.reset?.clickFn;
    const vals: Recordable = {};
    const rawVals = getFieldsValue();
    Object.keys(rawVals).forEach(
      (k) => rawVals[k] !== '' && rawVals[k] !== null && set(vals, k, rawVals[k]),
    );
    customClickFnc ? customClickFnc(rawVals) : resetFields();
  }

  async function handleToolbarBtnClick(type: ToolbarType, schema: FormSchema) {
    switch (type) {
      case 'edit':
        if (isFunction(getProps.value.onToolbarEditEvent)) {
          currentShowToolbarFiled.value = void 0;
          const res = await getProps.value.onToolbarEditEvent(cloneDeep(schema));
          updateSchema(res);
        } else {
          console.error('未注册 onToolbarEditEvent');
        }
        break;
      case 'copy':
        if (isFunction(getProps.value.onToolbarCopyEvent)) {
          currentShowToolbarFiled.value = void 0;
          getProps.value.onToolbarCopyEvent(cloneDeep(schema));
        } else {
          console.error('未注册 onToolbarCopyEvent');
        }
        break;
      case 'delete':
        uni.showModal({
          title: '删除',
          content: '确定要删除当前项吗?',
          confirmText: '立即删除',
          confirmColor: '#EA5E0E',
          cancelText: '取消',
          cancelColor: '#999996',
          success: ({ confirm }) => {
            if (confirm) {
              currentShowToolbarFiled.value = void 0;
              removeSchemaByFiled(schema.field);
            }
          },
        });
        break;
      case 'up':
      case 'down':
        const index = getSchema.value.findIndex((item) => item.field === schema.field);
        if (type === 'up' && index === 0) return;
        if (type === 'down' && index === getSchema.value.length - 1) return;
        const newSchema = getSchema.value.splice(index, 1)[0];
        getSchema.value.splice(index + (type === 'up' ? -1 : 1), 0, newSchema);
        break;
    }
  }

  const formActionType: FormActionType = {
    getSchemas: () => Promise.resolve(getSchema.value),
    getFieldsValue,
    setFieldsValue,
    resetFields,
    updateSchema,
    resetSchema,
    setProps,
    removeSchemaByFiled,
    appendSchemaByField,
    clearValidate,
    validate,
    submit: handleSubmit,
    scrollToField,
  };

  onMounted(() => {
    initDefault();
    emit('register', formActionType);
  });
</script>
<style lang="scss" scoped>
  .form-items {
    padding: 0 30rpx;
    overflow: hidden;
    position: relative;
  }
</style>
